﻿
using Dapper;
using HBase;
 
using MongoDB.Bson;
using MongoDB.Driver;
using Net.http;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;

namespace hCommand {

    public delegate void ParamDelegate( );
    [Serializable]
    public abstract class GkTransaction : Sw {
        public static bool dev = true;
        public  bool db_lock = true;
        public String name;
        public GkTransaction() {
            name = this.GetType().Name;
        }
        protected virtual String getTransKey() {
            return "in_out_lock";//出库入库同都变更货位需要同一把锁
        }
        protected virtual String p() {
            return JsonUtil.toView(this);
        }

        private IDbConnection conn;
        private IDbTransaction tran;

      
        public TransRes doWork(ParamDelegate initPram) {
            lock (this) {
                try {
                    begigTran();
                } catch (Exception e) {
                    if (conn != null) {
                        LoggerCommon.error(InfoCode.error_transaction, "事务开启异常", e);
                        conn.Close();
                        conn.Open();
                    }
                    return new TransRes("开启事务异常,请重试3次");
                }
                long time = DateTime.Now.Ticks / 10000;
                try {
                    initPram();
                    TransRes res = Execute();
                    if (res.s) {
                        tran.Commit();
                    } else {
                        tran.Rollback();
                    }
                    log(res.msg, time);
                    return res;
                }  catch (Exception ex) {
                    LoggerCommon.error(InfoCode.error_transaction, ex.Message, ex);
                    log(ex.Message + ex.StackTrace, time);
                    tran.Rollback(); 
                    return new TransRes(ex.Message);
                } finally {
                    if (conn.State == ConnectionState.Open) {
                        conn.Close();
                    }
                }
            }
            
        }

   
        void begigTran() {
            if (conn == null) {
                conn = DBUtils.newWMSConn(BaseConfig.prefixal);
            }
            if (conn.State == ConnectionState.Closed) {
                conn.Open();
            }
            tran = conn.BeginTransaction();
           
            if (db_lock) {
                if (dev) {
                    int count1 = queryUnique<int>("select count(*) from b_lock  where key_=@key", new { key = getTransKey() });
                    if (count1 == 0) {
                        exec("insert into b_lock(v,key_) values (1,@key)", new { key = getTransKey() });
                    }
                } 
                exec("update b_lock set v=v+1  where key_= @key", new { key = getTransKey() });
            }
        }
        void log(String error ,long begin) {
            try {
                if( LoggerCommon.loggerMongon ) {
                    var now= DateTime.Now;
                    long time = now.Ticks / 10000 - begin;
                    IMongoCollection<BsonDocument> collection = ConnectionCache.getMongoCollection<GkTransaction>();
                    BsonDocument document = new BsonDocument {
                        { "info", name + "》" + p() + "》" + error },
                        { "time",now },
                        { "ip", NetConfig.MeIp },
                        { "use", (int)time },
                        { "_id", HUtil.to64() }
                    };
                    collection.InsertOne(document);
                }
            } catch (Exception e){
                LoggerCommon.error(InfoCode.error_transaction, e.Message, e);
            }
        }

        protected abstract TransRes Execute();

        public T getById<T>(long id) where T : class {
            return conn.GetById<T>(id , tran);
        }

        public List<T> query<T>(String sql,object obj=null) {
            return conn.Query<T>(sql, obj, tran).ToList();
        }
        public T  queryUnique<T>(String sql, object obj = null) {
            return conn.QueryUnique<T>(sql, obj, tran);
        }

    
        public  bool update<T>( T t, Expression<Func<T, object>> properties=null) where T : class
        {
            return conn.Update(t, properties, tran);
        }

        
        public int batchInsert<T>(List<T> entities) where T : class {
            return conn.BatchInsert(entities, tran);
        }
        public long insert<T>(T t ) where T : class {
            return conn.Insert(t , tran);
        }
        public bool delete(BaseEntity t){
            return conn.delete(t,tran);
        }
        public  int exec(string sql ,object p) {
           return conn.Execute(sql ,p , tran);
        }
    }
}
